from alipay import AliPay, AliPayConfig
from fastapi import APIRouter, Depends, HTTPException,status
from sqlalchemy import select, update
import aiofiles

import settings
from models.order import Order
from models.seckill import *
from datetime import datetime
from schemas.response import SeckillListSchema, SeckillSchema
from hooks.dependencies import get_db_session
from models import AsyncSession
from utils.auth import AuthHandler
from schemas.request import BuySchema
auth_handler = AuthHandler()
router = APIRouter()

@router.get("/ing", response_model=SeckillListSchema)
async def get_ing(session:AsyncSession=Depends(get_db_session), page:int=1, size:int=10):
    # 秒杀中： start_time <=now, end_time >= now
    now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    offset = (page - 1) * size
    stmt = select(Seckill).where(Seckill.start_time<=now, Seckill.end_time>=now).order_by(Seckill.create_time.desc()).limit(size).offset(offset)

    result = await session.execute(stmt)
    rows = result.scalars().all()
    return {"seckills": rows}

@router.get("/will", response_model=SeckillListSchema)
async def get_will(session:AsyncSession=Depends(get_db_session), page:int=1, size:int=10):
    # 即将秒杀： start_time>=now
    now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    offset = (page - 1) * size
    stmt = select(Seckill).where(Seckill.start_time>=now).order_by(Seckill.create_time.desc()).limit(size).offset(offset)

    result = await session.execute(stmt)
    rows = result.scalars().all()
    return {"seckills": rows}

@router.get("/detail/{seckill_id}", response_model=SeckillSchema)
async def get_seckill_detaill(seckill_id:int, session:AsyncSession=Depends(get_db_session)):
    stmt = select(Seckill).where(Seckill.id==seckill_id)
    result = await session.execute(stmt)
    seckill_detail = result.scalar()
    if not seckill_detail:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail='秒杀信息不存在')
    return seckill_detail

@router.post("/lock")
async def mysql_lock(lid:int, session:AsyncSession=Depends(get_db_session)):
    seckid_id = 1913505211192705024
    # 实验锁  lid:1悲观  lid:0乐观
    if lid == 1:
        async with session.begin():
            result = await session.execute(select(Seckill).where(Seckill.id==seckid_id).with_for_update(read=True))
            seckill =  result.scalar()
            seckill.stock -= 1
    else:
        # 乐观锁
        async with session.begin():
            result = await session.execute(select(Seckill).where(Seckill.id==seckid_id))
            seckill =  result.scalar()
            if seckill.version_id != seckill.version_id:
                raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail='秒杀信息已被修改')
            seckill.stock -= 1
    return 'ok'

@router.post("/buy")
async def buy(data:BuySchema,  session:AsyncSession=Depends(get_db_session), user_id:int=Depends(auth_handler.auth_access_dependency)):
    seckill_id = data.seckill_id
    count = data.count
    address = data.address
    async with session.begin():
        result = await session.execute(select(Order).where(Order.user_id==user_id, Order.seckill_id==seckill_id))
        order = result.scalar()
        if order:
            raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail='您已经购买过该商品')
        secill_result = await session.execute(select(Seckill).where(Seckill.id==seckill_id).with_for_update())
        seckill = secill_result.scalar()
        if not seckill:
            raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail='秒杀信息不存在')
        if seckill.stock < count:
            raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail=f'库存不足,最多抢购{count if count>0 else 0}件')
        await session.execute(update(Seckill).where(Seckill.id==seckill_id).values(stock=Seckill.stock-count))
    async with session.begin():
        order = Order(user_id=user_id, seckill_id=seckill_id, count=count, address=address, amount=seckill.sk_price*count)
        session.add(order)
    # 读取配置文件
    async with aiofiles.open('keys/app_private.key', mode='r') as f:
        app_private_key_string = await f.read()
    async with aiofiles.open('keys/alipay_public.pem', mode='r') as f:
        alipay_public_key_string = await f.read()

    alipay = AliPay(
        appid=settings.ALIPAY_APP_ID,
        app_notify_url="http://www.example.com/order/alipay_notify",  # 默认回调 url
        app_private_key_string=app_private_key_string,
        alipay_public_key_string=alipay_public_key_string,
        sign_type="RSA2",  # RSA 或者 RSA2
        debug=True,  # 默认 False
        verbose=True,  # 输出调试数据
        config=AliPayConfig(timeout=15)  # 可选，请求超时时间
    )
    order_string = alipay.api_alipay_trade_app_pay(
        out_trade_no=str(order.id),
        total_amount=float(order.amount),
        subject=seckill.commodity.title
    )
    return {
        "alipay_order":order_string
    }

@router.get("/detail/{seckill_id}", response_model=SeckillSchema)
async def get_seckill_detail(seckill_id:int, session:AsyncSession=Depends(get_db_session)):
    async with session.begin():
        result = await session.execute(select(Seckill).where(Seckill.id==seckill_id))
        seckill = result.scalar()
        if not seckill:
            raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail='秒杀信息不存在')
        return seckill